import java.util.*;

public class Bill {
    public static void main(String[] args) {
        BillManager billManager = new BillManager();
        new menu(billManager);
    }
}

class Transaction {
    private int year;
    private int month;
    private int date;
    private double amount;
    private String category;
    private String remark;

    public Transaction(int year, int month, int date, double amount, String category, String remark) {
        this.year = year;
        this.month = month;
        this.date = date;
        this.amount = amount;
        this.category = category;
        this.remark = remark;
    }

    public int getYear() {
        return year;
    }

    public int getMonth() {
        return month;
    }

    public int getDate() {
        return date;
    }

    public double getAmount() {
        return amount;
    }

    public String getCategory() {
        return category;
    }

    public String getRemark() {
        return remark;
    }

}

class menu {
    public menu(BillManager billManager) {
        Scanner sc = new Scanner(System.in);
        System.out.println("==========================");
        System.out.println("   欢迎使用个人账单管理系统");
        System.out.println("==========================");
        System.out.println("请选择操作：");
        System.out.println("1.记录收入");
        System.out.println("2.记录支出");
        System.out.println("3.查看所有账单");
        System.out.println("4.查询账单");
        System.out.println("5.设置月度预算");
        System.out.println("6.查看月度统计报告");
        System.out.println("7.退出系统");
        System.out.println();
        System.out.print("请输入选择序号：");
        int choice = sc.nextInt();
        switch (choice) {
            case 1:
                new Income(billManager);
                break;
            case 2:
                new Outgo(billManager);
                break;
            case 3:
                billManager.displayTransactions();
                new menu(billManager);
                break;
            case 4:
                billManager.queryTransactions(4);
                new menu(billManager);
                break;
            case 5:
                sc.nextLine();
                System.out.println("请输入年份和月份来设置剩余预算（格式：YYYY-MM）：");
                String input = sc.nextLine();
                String[] parts = input.split("-");
                int year = Integer.parseInt(parts[0]);
                int month = Integer.parseInt(parts[1]);
                billManager.setMonthlyBudget(year, month);
                billManager.getRemainingBudget();
                new menu(billManager);
                break;
            case 6:
                sc.nextLine();
                System.out.println("请输入年份和月份进行月度统计（格式：YYYY-MM）：");
                String input1 = sc.nextLine();
                String[] parts1 = input1.split("-");
                int year1 = Integer.parseInt(parts1[0]);
                int month1 = Integer.parseInt(parts1[1]);
                billManager.monthlySummary(year1, month1);
                new menu(billManager);
                break;
            case 7:
                System.exit(0);
                break;
            default:
                System.out.println("无效的选择，请重新输入。");
                new menu(billManager);
                break;
        }
    }
}

class Income {
    public Income(BillManager billManager) {
        Scanner sc = new Scanner(System.in);
        System.out.println("==========================");
        System.out.println("   欢迎使用个人账单管理系统");
        System.out.println("==========================");
        System.out.println("请输入收入信息：");
        System.out.println("日期（YYYY-MM-DD）：");
        String[] parts = sc.nextLine().split("-");
        int year = Integer.parseInt(parts[0]);
        int month = Integer.parseInt(parts[1]);
        int date = Integer.parseInt(parts[2]);
        System.out.println("金额：");
        double amount = sc.nextDouble();
        System.out.println("类别（如工资、奖金等）：");
        String category = sc.next();
        System.out.println("备注：");
        String remark = sc.next();
        billManager.recordIncome(year, month, date, amount, category, remark);
        System.out.println();
        String g = sc.nextLine();
        System.out.println("按任意键返回主菜单...");
        g = sc.nextLine();
        new menu(billManager);
    }
}

class Outgo {
    public Outgo(BillManager billManager) {
        Scanner sc = new Scanner(System.in);
        System.out.println("==========================");
        System.out.println("   欢迎使用个人账单管理系统");
        System.out.println("==========================");
        System.out.println("请输入支出信息：");
        System.out.println("日期（YYYY-MM-DD）：");
        String[] parts = sc.nextLine().split("-");
        int year = Integer.parseInt(parts[0]);
        int month = Integer.parseInt(parts[1]);
        int date = Integer.parseInt(parts[2]);
        System.out.println("金额：");
        double amount = sc.nextDouble();
        System.out.println("类别（如餐饮交通购物等）：");
        String category = sc.next();
        System.out.println("备注：");
        String remark = sc.next();
        billManager.recordExpense(year, month, date, amount, category, remark);
        System.out.println();
        String g = sc.nextLine();
        System.out.println("按任意键返回主菜单...");
        g = sc.nextLine();
        new menu(billManager);
    }

}

class BillManager {
    List<Transaction> incomeList = new ArrayList<>();
    List<Transaction> expenseList = new ArrayList<>();
    Scanner sc = new Scanner(System.in);
    private double monthlyBudget;
    private int budgetYear;
    private int budgetMonth;
    private double currentMonthExpense;

    public void setMonthlyBudget(int year, int month) {
        System.out.println("请输入月度预算金额：");
        this.monthlyBudget = sc.nextDouble();
        this.budgetYear = year;
        this.budgetMonth = month;
        System.out.println("月度预算已设置为：" + monthlyBudget);
    }

    public double getRemainingBudget() {
        // 计算当前月份的总支出
        currentMonthExpense = calculateExpenseForMonth(budgetYear, budgetMonth);
        // 计算剩余预算
        double remaining = monthlyBudget - currentMonthExpense;
        if (remaining < 0) {
            System.out.println("当前支出已超出预算：" + (-remaining));
        } else {
            System.out.println("当前月剩余可用预算：" + remaining);
        }
        return remaining;
    }

    private double calculateExpenseForMonth(int year, int month) {
        double totalExpense = 0;
        for (Transaction transaction : expenseList) {
            if (transaction.getYear() == year && transaction.getMonth() == month) {
                totalExpense += transaction.getAmount();
            }
        }
        return totalExpense;
    }

    public void monthlySummary(int year, int month) {
        double totalIncome = 0;
        double totalExpense = 0;
        Map<String, Double> categoryExpenseMap = new HashMap<>();

        for (Transaction transaction : incomeList) {
            if (transaction.getYear() == year && transaction.getMonth() == month) {
                totalIncome += transaction.getAmount();
            }
        }

        for (Transaction transaction : expenseList) {
            if (transaction.getYear() == year && transaction.getMonth() == month) {
                totalExpense += transaction.getAmount();
                categoryExpenseMap.merge(transaction.getCategory(), transaction.getAmount(), Double::sum);
            }
        }

        System.out.printf("年份：%d, 月份：%02d\n", year, month);
        System.out.printf("总收入：%.2f\n", totalIncome);
        System.out.printf("总支出：%.2f\n", totalExpense);
        System.out.println("各类别支出：");
        categoryExpenseMap.forEach((category, amount) -> System.out.printf("%s: %.2f\n", category, amount));
    }

    public void recordIncome(int year, int month, int date, double amount, String category, String remark) {
        if (amount > 0) {
            incomeList.add(new Transaction(year, month, date, amount, category, remark));
            System.out.println("收入已成功记录!");
        } else {
            System.out.println("金额小于0录不进去");
        }
    }

    public void recordExpense(int year, int month, int date, double amount, String category, String remark) {
        if (amount > 0) {
            expenseList.add(new Transaction(year, month, date, amount, category, remark));
            System.out.println("支出已成功记录!");
        } else {
            System.out.println("金额小于0录不进去");
        }
    }

    public void displayTransactions() {
        if (incomeList.isEmpty() && expenseList.isEmpty()) {
            System.out.println("没有账单记录。");
            return;
        }
        System.out.println("\n所有收入记录：");
        for (int i = 0; i < incomeList.size(); i++) {
            Transaction transaction = incomeList.get(i);
            printTransaction(transaction);
        }
        System.out.println("\n所有支出记录：");
        for (Transaction transaction : expenseList) {
            printTransaction(transaction);
        }
    }

    private void printTransaction(Transaction transaction) {
        System.out.printf("日期：%d-%02d-%02d, 金额：%.2f, 类别：%s, 备注：%s",
                transaction.getYear(), transaction.getMonth(), transaction.getDate(),
                transaction.getAmount(), transaction.getCategory(), transaction.getRemark());
        System.out.println();
    }


    public void queryTransactions(int type) {
        Scanner sc = new Scanner(System.in);
        List<Transaction> result1 = new ArrayList<>();
        List<Transaction> result2 = new ArrayList<>();

        if (type == 4) {
            System.out.println("请输入查询类型（1:日期, 2:日期范围, 3:类别）：");
            type = sc.nextInt();
            sc.nextLine();
            if (type == 1) {
                // 按日期查询
                System.out.println("请输入查询日期（YYYY-MM-DD）：");
                String[] parts = sc.nextLine().split("-");
                int year = Integer.parseInt(parts[0]);
                int month = Integer.parseInt(parts[1]);
                int date = Integer.parseInt(parts[2]);
                queryByDate(year, month, date, result1, result2);
            } else if (type == 2) {
                // 按日期范围查询
                System.out.println("请输入开始日期（YYYY-MM-DD）：");
                String[] parts = sc.nextLine().split("-");
                int startYear = Integer.parseInt(parts[0]);
                int startMonth = Integer.parseInt(parts[1]);
                int startDay = Integer.parseInt(parts[2]);
                System.out.println("请输入结束日期（YYYY-MM-DD）：");
                String[] part = sc.nextLine().split("-");
                int endYear = Integer.parseInt(part[0]);
                int endMonth = Integer.parseInt(part[1]);
                int endDay = Integer.parseInt(part[2]);
                queryByRange(startYear, startMonth, startDay, endYear, endMonth, endDay, result1, result2);
            } else if (type == 3) {
                // 按类别查询
                System.out.println("请输入类别：");
                String category = sc.next();
                queryByCategory(category, result1, result2);
            }
        }
        int n = 0;
        if (!result1.isEmpty()) {
            n = 1;
            System.out.println("符合条件的收入记录：");
            for (Transaction transaction : result1) {
                printTransaction(transaction);
            }
        }
        if (!result2.isEmpty()) {
            n = 1;
            System.out.println("符合条件的支出记录：");
            for (Transaction transaction : result2) {
                printTransaction(transaction);
            }
        }
        if (n == 0) {
            System.out.println("没有找到符合条件的账单记录。");
        }
    }

    private void queryByDate(int year, int month, int date, List<Transaction> result1, List<Transaction> result2) {
        for (Transaction transaction : incomeList) {
            if (transaction.getYear() == year && transaction.getMonth() == month && transaction.getDate() == date) {
                result1.add(transaction);
            }
        }
        for (Transaction transaction : expenseList) {
            if (transaction.getYear() == year && transaction.getMonth() == month && transaction.getDate() == date) {
                result2.add(transaction);
            }
        }
    }

    private void queryByRange(int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay, List<Transaction> result1, List<Transaction> result2) {
        for (Transaction transaction : incomeList) {
            if (((transaction.getYear() > startYear) ||
                    (transaction.getYear() == startYear && transaction.getMonth() > startMonth) ||
                    (transaction.getYear() == startYear && transaction.getMonth() == startMonth && transaction.getDate() >= startDay)) &&
                    ((transaction.getYear() < endYear) ||
                            (transaction.getYear() == endYear && transaction.getMonth() < endMonth) ||
                            (transaction.getYear() == endYear && transaction.getMonth() == endMonth && transaction.getDate() <= endDay))) {
                result1.add(transaction);
            }
        }
        for (Transaction transaction : expenseList) {
            if (((transaction.getYear() > startYear) ||
                    (transaction.getYear() == startYear && transaction.getMonth() > startMonth) ||
                    (transaction.getYear() == startYear && transaction.getMonth() == startMonth && transaction.getDate() >= startDay)) &&
                    ((transaction.getYear() < endYear) ||
                            (transaction.getYear() == endYear && transaction.getMonth() < endMonth) ||
                            (transaction.getYear() == endYear && transaction.getMonth() == endMonth && transaction.getDate() <= endDay))) {
                result2.add(transaction);
            }
        }
    }

    private void queryByCategory(String category, List<Transaction> result1, List<Transaction> result2) {
        for (Transaction transaction : incomeList) {
            if (transaction.getCategory().equals(category)) {
                result1.add(transaction);
            }
        }
        for (Transaction transaction : expenseList) {
            if (transaction.getCategory().equals(category)) {
                result2.add(transaction);
            }
        }
    }

}